package net.mxox.apps.ant;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.mxox.apps.util.Native2AsciiUtils;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

public class ConfTask extends Task {
	private static Pattern pattern = Pattern.compile("\\$!?\\{(.+?)\\}");
	
	private String vm;
	private String destPath;
	private String propPath;

	public void execute() {
		if(check()) {
			merge();
		} else {
			throw new BuildException(propPath+" not well prepared");
		}
	}
	
	private boolean check() {
		boolean checkSuccessed=true;
		try {
			Scanner in = new Scanner(new File(vm));
			File propFile = new File(propPath);
			if(!propFile.exists()) {
				propFile.createNewFile();
			}
			FileInputStream fis = new FileInputStream(propFile);
			Properties prop = new Properties();
			prop.load(fis);
			
			StringBuilder sb = new StringBuilder();
			while(in.hasNextLine()) {
				String line = in.nextLine().trim();
				sb.append(line);
			}
			Matcher m = pattern.matcher(sb);
			while(m.find()) {
				String key = m.group(1).replace('_', '.');
				if(!prop.containsKey(key) ||(((String)prop.get(key)).trim().length()==0)) {
					checkSuccessed=false;
					log(key+" needed for " + vm);
					prop.put(key, "########Set Your Custome Value Here!########");
				}
			}
			if(!checkSuccessed) {
				storeNewProperties(prop);
			}
		} catch (Exception e) {
			throw new BuildException(e);
		}
		return checkSuccessed;
	}
	
	private void storeNewProperties(Properties prop) {
		try {
			BufferedWriter bw = new BufferedWriter(new PrintWriter(new File(propPath)));
			List<String> keyList = new ArrayList<String>();
			Set<Object> keySet = prop.keySet();
			for (Object key : keySet) {
				keyList.add((String)key);
			}
			Collections.sort(keyList);
			
			for (String key : keyList) {
				String val = (String) prop.get(key);
				key = Native2AsciiUtils.native2Ascii(key);
				val = Native2AsciiUtils.native2Ascii(val);
				if(val.equals("########Set Your Custome Value Here!########")) {
					bw.write("#");
				}
				bw.write(key + "=" + val);
				bw.newLine();
			}
			bw.flush();
		} catch (Exception e) {
			throw new BuildException(e);
		}
	}
	
	private void merge() {
		VelocityEngine ve = new VelocityEngine();
		File vmFile = new File(vm);
		ve.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, vmFile.getParent());
		ve.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS,
				"org.apache.velocity.runtime.log.NullLogSystem");
		try {
			ve.init();
			Template t = ve.getTemplate(vmFile.getName());
			VelocityContext context = new VelocityContext();

			FileInputStream fis = new FileInputStream(propPath);
			
			Properties prop = new Properties();
			prop.load(fis);
			Enumeration<Object> enu = prop.keys();
			while (enu.hasMoreElements()) {
				String key = enu.nextElement().toString();
				String value = prop.get(key).toString();
				if(destPath.endsWith(".properties")) {
					value=Native2AsciiUtils.native2Ascii(value);
				}
				context.put(key.replace('.', '_'), value);
			}

			BufferedWriter writer = new BufferedWriter(new FileWriter(destPath));
			t.merge(context, writer);
			writer.flush();
			writer.close();
			log("Generated config file: " + destPath + " from template: " + vm + " using properties: " + propPath, Project.MSG_INFO);
		} catch (Exception e) {
			throw new BuildException(e);
		}
	}

	public void setVm(String vm) {
		this.vm = vm;
	}

	public void setDestPath(String destPath) {
		this.destPath = destPath;
	}

	public void setPropPath(String propPath) {
		this.propPath = propPath;
	}

}
